{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# function call\n",
    "\n",
    "## 简介\n",
    "\n",
    "function_call，顾名思义，通过给大模型提供 function 的说明描述，以及对应的入参出参 schema，让大模型输出 function 调用策略，结合多轮对话，以最终实现一个复杂的任务。\n",
    "以下将以天气获取为例子，通过千帆 Python SDK提供的 ERNIE-Bot 大模型以实现通过大模型得到对应城市的天气情况。\n",
    "\n",
    "本教程可使用的最低 langchain 版本为 0.1.10\n",
    "\n",
    "## 准备\n",
    "\n",
    "本文使用了 Langchain 中的的 agent 以及 tool 。首先安装千帆 Python SDK 和 Langchain："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#-# cell_skip\n",
    "!pip install qianfan\n",
    "!pip install langchain"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你已经安装了千帆 Python SDK 和 Langchain，我们建议进行一次升级"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#-# cell_skip\n",
    "!pip install -U qianfan\n",
    "!pip install -U langchain"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "并且初始化我们所需要的凭证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化LLM\n",
    "import os\n",
    "\n",
    "os.environ['QIANFAN_AK'] = ''\n",
    "os.environ['QIANFAN_SK'] = ''"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义工具\n",
    "\n",
    "这一步需要定义使用的工具，以及它的参数和描述，以上信息会影响到大模型对工具的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from enum import Enum\n",
    "\n",
    "from langchain.agents import tool\n",
    "from langchain.pydantic_v1 import BaseModel, Field\n",
    "\n",
    "\n",
    "class TemperatureUnitEnum(str, Enum):\n",
    "    celsius: str = \"摄氏度\"\n",
    "    fahrenheit: str = \"华氏度\"\n",
    "\n",
    "\n",
    "class WeatherToolSchema(BaseModel):\n",
    "    \"\"\"获得指定地点的天气\"\"\"\n",
    "\n",
    "    location: str = Field(description=\"省，市名，例如：河北省，石家庄\")\n",
    "    unit: TemperatureUnitEnum = Field(description=\"温度单位\")\n",
    "\n",
    "@tool(args_schema=WeatherToolSchema)\n",
    "def get_current_weather(location: str, unit: TemperatureUnitEnum) -> str:\n",
    "    \"\"\"获得指定地点的天气\"\"\"\n",
    "    return \"25\"\n",
    "\n",
    "tools = [get_current_weather]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在 Agent 中使用工具"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[WARNING] [03-28 18:13:40] base.py:526 [t:8094817088]: This key `functions` does not seem to be a parameter that the model `ERNIE-Bot-turbo` will accept\n",
      "[INFO] [03-28 18:13:40] openapi_requestor.py:336 [t:8094817088]: requesting llm api endpoint: /chat/ernie-3.5-8k-0205\n",
      "[WARNING] [03-28 18:13:43] base.py:526 [t:8094817088]: This key `functions` does not seem to be a parameter that the model `ERNIE-Bot-turbo` will accept\n",
      "[INFO] [03-28 18:13:43] openapi_requestor.py:336 [t:8094817088]: requesting llm api endpoint: /chat/ernie-3.5-8k-0205\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32;1m\u001b[1;3mcontent='' additional_kwargs={'finish_reason': 'function_call', 'request_id': 'as-znt9w4kw8q', 'object': 'chat.completion', 'search_info': []} response_metadata={'token_usage': {'prompt_tokens': 277, 'completion_tokens': 38, 'total_tokens': 315}, 'model_name': 'ERNIE-Bot-turbo', 'finish_reason': 'function_call', 'id': 'as-znt9w4kw8q', 'object': 'chat.completion', 'created': 1711620823, 'result': '', 'is_truncated': False, 'need_clear_history': False, 'function_call': {'name': 'get_current_weather', 'thoughts': \"用户想要知道今天上海的气温是多少摄氏度，我需要调用'get_current_weather'工具来获取信息。\", 'arguments': '{\"location\":\"上海\",\"unit\":\"摄氏度\"}'}, 'usage': {'prompt_tokens': 277, 'completion_tokens': 38, 'total_tokens': 315}}\u001b[0m\u001b[36;1m\u001b[1;3m25\u001b[0m\u001b[32;1m\u001b[1;3mcontent='今天上海的气温是25摄氏度。如果您需要更多天气信息或有其他问题，请随时告诉我。' additional_kwargs={'finish_reason': 'normal', 'request_id': 'as-ic6swnfrmy', 'object': 'chat.completion', 'search_info': []} response_metadata={'token_usage': {'prompt_tokens': 284, 'completion_tokens': 22, 'total_tokens': 306}, 'model_name': 'ERNIE-Bot-turbo', 'finish_reason': 'normal', 'id': 'as-ic6swnfrmy', 'object': 'chat.completion', 'created': 1711620826, 'result': '今天上海的气温是25摄氏度。如果您需要更多天气信息或有其他问题，请随时告诉我。', 'is_truncated': False, 'need_clear_history': False, 'usage': {'prompt_tokens': 284, 'completion_tokens': 22, 'total_tokens': 306}}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': '今天上海的气温是多少摄氏度', 'output': '今天上海的气温是25摄氏度。如果您需要更多天气信息或有其他问题，请随时告诉我。'}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.agents import AgentExecutor\n",
    "\n",
    "from langchain.chat_models import QianfanChatEndpoint\n",
    "from qianfan.extensions.langchain.agents import QianfanSingleActionAgent\n",
    "\n",
    "\n",
    "llm = QianfanChatEndpoint(endpoint=\"ernie-3.5-8k-0205\")\n",
    "agent = QianfanSingleActionAgent.from_system_prompt(tools, llm)\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "\n",
    "agent_executor.invoke(\"今天上海的气温是多少摄氏度\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "58f7cb64c3a06383b7f18d2a11305edccbad427293a2b4afa7abe8bfc810d4bb"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
